/*
 * ESP32-C3 UART异步收发示例代码
 * 本代码实现了UART1的异步接收和发送功能，使用中断方式接收数据
 * 并通过FreeRTOS队列处理UART事件
 *
 * 硬件连接：
 * - TXD_PIN: GPIO_NUM_4 (发送引脚)
 * - RXD_PIN: GPIO_NUM_5 (接收引脚)
 */
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"

// 定义接收缓冲区大小
static const int RX_BUF_SIZE = 1024;

// 定义UART引脚
#define TXD_PIN (GPIO_NUM_4)  // 发送引脚
#define RXD_PIN (GPIO_NUM_5)  // 接收引脚

// 定义事件队列句柄，用于接收UART事件通知
static QueueHandle_t uart_queue;

/**
 * @brief UART初始化函数
 * 配置UART参数、安装驱动、设置引脚并启用中断
 */
void init(void)
{
    // UART配置结构体
    const uart_config_t uart_config = {
        .baud_rate = 115200,       // 波特率115200
        .data_bits = UART_DATA_8_BITS,  // 8位数据位
        .parity = UART_PARITY_DISABLE,  // 禁用奇偶校验
        .stop_bits = UART_STOP_BITS_1,  // 1位停止位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,  // 禁用硬件流控
        .source_clk = UART_SCLK_DEFAULT,  // 使用默认时钟源
    };
    // 安装UART驱动并创建事件队列
    // 参数：UART端口号，接收缓冲区大小，发送缓冲区大小，队列长度，队列句柄，标志
    uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, RX_BUF_SIZE * 2, 10, &uart_queue, 0);
    // 配置UART参数
    uart_param_config(UART_NUM_1, &uart_config);
    // 设置UART引脚
    uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    
    // 使能UART接收中断
    uart_enable_rx_intr(UART_NUM_1);
}

/**
 * @brief 发送数据函数
 * @param logName 日志标签
 * @param data 要发送的数据
 * @return 实际发送的字节数
 */
int sendData(const char* logName, const char* data)
{
    const int len = strlen(data);
    const int txBytes = uart_write_bytes(UART_NUM_1, data, len);
    ESP_LOGI(logName, "Wrote %d bytes", txBytes);
    return txBytes;
}

/**
 * @brief 发送任务函数
 * 周期性发送数据
 * @param arg 任务参数(未使用)
 */
static void tx_task(void *arg)
{
    static const char *TX_TASK_TAG = "TX_TASK";
    esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    while (1) {
        sendData(TX_TASK_TAG, "Hello AAA");  // 发送数据
        vTaskDelay(2000 / portTICK_PERIOD_MS);  // 延时2秒
    }
}

/**
 * @brief 接收任务函数
 * 等待并处理UART事件
 * @param arg 任务参数(未使用)
 */
static void rx_task(void *arg)
{
    static const char *RX_TASK_TAG = "RX_TASK";
    esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
    uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE + 1);  // 分配接收缓冲区
    uart_event_t event;  // UART事件结构体
    
    while (1) {
        // 等待UART事件
        if (xQueueReceive(uart_queue, (void * )&event, (TickType_t)portMAX_DELAY)) {
            switch (event.type) {
                // 接收数据事件
                case UART_DATA:
                    // 读取接收到的数据
                    int rxBytes = uart_read_bytes(UART_NUM_1, data, event.size, 0);
                    if (rxBytes > 0) {
                        data[rxBytes] = 0;  // 添加字符串结束符
                        ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
                        ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
                    }
                    break;
                
                // FIFO溢出事件
                case UART_FIFO_OVF:
                    ESP_LOGW(RX_TASK_TAG, "FIFO overflow event");
                    uart_flush_input(UART_NUM_1);  // 刷新输入缓冲区
                    xQueueReset(uart_queue);  // 重置队列
                    break;
                // 缓冲区满事件
                case UART_BUFFER_FULL:
                    ESP_LOGW(RX_TASK_TAG, "Buffer full event");
                    uart_flush_input(UART_NUM_1);  // 刷新输入缓冲区
                    xQueueReset(uart_queue);  // 重置队列
                    break;
                // 奇偶校验错误事件
                case UART_PARITY_ERR:
                    ESP_LOGW(RX_TASK_TAG, "Parity error event");
                    break;
                // 帧错误事件
                case UART_FRAME_ERR:
                    ESP_LOGW(RX_TASK_TAG, "Frame error event");
                    break;
                // 未知事件类型
                default:
                    ESP_LOGW(RX_TASK_TAG, "Unknown event type: %d", event.type);
                    break;
            }
        }
    }
    free(data);  // 释放缓冲区(注：由于while(1)循环，此处代码不会执行到)
}

/**
 * @brief 应用主函数
 * 初始化UART并创建任务
 */
void app_main(void)
{
    init();  // 初始化UART
    // 创建接收任务，优先级较高
    xTaskCreate(rx_task, "uart_rx_task", 1024 * 2, NULL, configMAX_PRIORITIES - 1, NULL);
    // 创建发送任务，优先级较低
    xTaskCreate(tx_task, "uart_tx_task", 1024 * 2, NULL, configMAX_PRIORITIES - 2, NULL);
}